/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */

package com.pig4cloud.pigx.wallet.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import com.pig4cloud.pigx.user.entity.User;
import com.pig4cloud.pigx.wallet.api.feign.RemoteRippleUserService;
import com.pig4cloud.pigx.wallet.bo.WalletStatisticsBO;
import com.pig4cloud.pigx.wallet.constant.WalletConstant;
import com.pig4cloud.pigx.wallet.constant.WalletStatusEnum;
import com.pig4cloud.pigx.wallet.dto.ChargeMentionNotificationDTO;
import com.pig4cloud.pigx.wallet.entity.Account;
import com.pig4cloud.pigx.wallet.entity.CapitalAccount;
import com.pig4cloud.pigx.wallet.entity.Notification;
import com.pig4cloud.pigx.wallet.entity.WithdrawalRecord;
import com.pig4cloud.pigx.wallet.mapstruct.NotificationStruct;
import com.pig4cloud.pigx.wallet.service.AccountService;
import com.pig4cloud.pigx.wallet.service.CapitalAccountService;
import com.pig4cloud.pigx.wallet.service.CurrencyService;
import com.pig4cloud.pigx.wallet.service.NotificationService;
import com.pig4cloud.pigx.wallet.service.WithdrawalRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 提现记录
 *
 * @author
 * @date 2022-08-15 14:16:30
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/withdrawalrecord")
@Api(value = "withdrawalrecord", tags = "提现记录管理")
public class WithdrawalRecordController {

	private final WithdrawalRecordService withdrawalRecordService;
	private final AccountService accountService;
	private final CapitalAccountService capitalAccountService;
	private final RabbitTemplate rabbitTemplate;
	private final CurrencyService currencyService;
	private final StringRedisTemplate stringRedisTemplate;
	private final RemoteRippleUserService remoteRippleUserService;
	/** 用户消息通知 */
	private final NotificationService notificationService;

	/**
	 * 分页查询
	 *
	 * @param page             分页对象
	 * @param withdrawalRecord 提现记录
	 * @return
	 */
	@ApiOperation(value = "分页查询", notes = "分页查询")
	@GetMapping("/page")
	@PreAuthorize("@pms.hasPermission('wallet_withdrawalrecord_view')")
	public R<WalletStatisticsBO<WithdrawalRecord>> getWithdrawalRecordPage(Page<WithdrawalRecord> page, WithdrawalRecord withdrawalRecord) {
		// 查询条件
		QueryWrapper<WithdrawalRecord> wrapper = new QueryWrapper<WithdrawalRecord>(){{
			if (withdrawalRecord.getUserId() != null) {
				eq("user_id", withdrawalRecord.getUserId());
			}
			if (StrUtil.isNotBlank(withdrawalRecord.getCurrency())) {
				eq("currency", withdrawalRecord.getCurrency());
			}
			if (StrUtil.isNotBlank(withdrawalRecord.getPublicChain())) {
				eq("public_chain", withdrawalRecord.getPublicChain());
			}
			if (withdrawalRecord.getStartTime() != null) {
				ge("create_time", withdrawalRecord.getStartTime());
				le("create_time", withdrawalRecord.getStartTime() == null ? withdrawalRecord.getStartTime() : withdrawalRecord.getStartTime().plusDays(1));
			}
			if (withdrawalRecord.getState() != null) {
				eq("state",withdrawalRecord.getState());
			}
			orderByDesc("create_time");
		}};
		Page<WithdrawalRecord> pageList = withdrawalRecordService.page(page, wrapper);
		List<WithdrawalRecord> records = pageList.getRecords();
		if (CollUtil.isNotEmpty(records)) {
			List<Long> collect = records.stream().map(WithdrawalRecord::getUserId).collect(Collectors.toList());
			R<List<User>> userList = remoteRippleUserService.getUserList(collect, SecurityConstants.FROM_IN);
			List<User> data = userList.getData();
			records.forEach(record -> {
				data.forEach(item -> {
					if (record.getUserId().equals(item.getUid())) {
						record.setEmail(item.getEmail());
					}
				});
			});
		}
		WalletStatisticsBO<WithdrawalRecord> bo = new WalletStatisticsBO<>();
		// 统计数据
		WithdrawalRecord one = withdrawalRecordService.getOne(wrapper.select(
				"sum(quantity) 'quantity'",
				"sum(service_charge) 'serviceCharge'",
				"sum(actual_withdrawal_amount) 'actualWithdrawalAmount'"
		));
		bo.setPage(pageList);
		bo.setStatistics(one);
		return R.ok(bo);
	}


	/**
	 * 通过id查询提现记录
	 *
	 * @param id id
	 * @return R
	 */
	@ApiOperation(value = "通过id查询", notes = "通过id查询")
	@GetMapping("/{id}")
	@PreAuthorize("@pms.hasPermission('wallet_withdrawalrecord_view')")
	public R getById(@PathVariable("id") Long id) {
		return R.ok(withdrawalRecordService.getById(id));
	}

	/**
	 * 新增提现记录
	 *
	 * @param withdrawalRecord 提现记录
	 * @return R
	 */
	@ApiOperation(value = "新增提现记录", notes = "新增提现记录")
	@SysLog("新增提现记录")
	@PostMapping
	@PreAuthorize("@pms.hasPermission('wallet_withdrawalrecord_add')")
	public R save(@RequestBody WithdrawalRecord withdrawalRecord) {
		return R.ok(withdrawalRecordService.save(withdrawalRecord));
	}

	/**
	 * 修改提现记录
	 *
	 * @param withdrawalRecord 提现记录
	 * @return R
	 */
	@ApiOperation(value = "修改提现记录", notes = "修改提现记录")
	@SysLog("修改提现记录")
	@PutMapping
	@PreAuthorize("@pms.hasPermission('wallet_withdrawalrecord_edit')")
	public R updateById(@RequestBody WithdrawalRecord withdrawalRecord) {
		return R.ok(withdrawalRecordService.updateById(withdrawalRecord));
	}

	/**
	 * 通过id删除提现记录
	 *
	 * @param id id
	 * @return R
	 */
	@ApiOperation(value = "通过id删除提现记录", notes = "通过id删除提现记录")
	@SysLog("通过id删除提现记录")
	@DeleteMapping("/{id}")
	@PreAuthorize("@pms.hasPermission('wallet_withdrawalrecord_del')")
	public R removeById(@PathVariable Long id) {
		return R.ok(withdrawalRecordService.removeById(id));
	}


	/**
	 * 导出excel 表格
	 *
	 * @param withdrawalRecord 查询条件
	 * @return excel 文件流
	 */
	@ResponseExcel
	@GetMapping("/export")
	@PreAuthorize("@pms.hasPermission('wallet_withdrawalrecord_export')")
	public List<WithdrawalRecord> export(WithdrawalRecord withdrawalRecord) {
		return withdrawalRecordService.list(Wrappers.query(withdrawalRecord));
	}

	/**
	 * 生成提现记录
	 */
//	@Inner(false)
	@ApiOperation(value = "生成提现记录", notes = "生成提现记录")
	@PostMapping("/create")
	@Transactional(rollbackFor = Exception.class)
	public R create(@RequestBody WithdrawalRecord withdrawalRecord) {

		Long userId = SecurityUtils.getUser().getId();

		String codeRedis = stringRedisTemplate.opsForValue().get("wallet:email:code:" + userId);

		if (!StrUtil.equals(withdrawalRecord.getCode(), codeRedis)) {
			return R.failed("验证码错误！");
		}

		R<User> userByUid = remoteRippleUserService.getUserByUserId(userId, SecurityConstants.FROM_IN);

		if (!StrUtil.equals(withdrawalRecord.getPassword(), userByUid.getData().getMoneyPassword())) {
			return R.failed("密码错误！");
		}

		Account account = accountService.getOne(new LambdaQueryWrapper<Account>()
				.eq(Account::getUserId, userId)
				.eq(Account::getMainNetwork, withdrawalRecord.getPublicChain())
		);
		CapitalAccount capitalAccount = capitalAccountService.getOne(new LambdaQueryWrapper<CapitalAccount>()
				.eq(CapitalAccount::getUserId, userId)
		);

		int compare = capitalAccount.getAvailable().compareTo(withdrawalRecord.getQuantity());
		if (compare < 0) {
			return R.failed("余额不足！");
		}

		WithdrawalRecord withdrawalRecordSave = new WithdrawalRecord();

		BeanUtil.copyProperties(withdrawalRecord, withdrawalRecordSave);

		withdrawalRecordSave.setId(IdUtil.getSnowflakeNextId());
		withdrawalRecordSave.setState(WalletStatusEnum.UNDER_REVIEW.getStatus());
		withdrawalRecordSave.setAccountId(account.getId());
		withdrawalRecordSave.setUserId(userId);
		withdrawalRecordSave.setCurrency(WalletConstant.USDT);
		withdrawalRecordService.save(withdrawalRecordSave);

		// 封装充提通知参数
		ChargeMentionNotificationDTO notificationDTO = new ChargeMentionNotificationDTO(withdrawalRecordSave);
		notificationDTO.setLanguage(userByUid.getData().getLanguageCode());
		// 用户消息通知
		Notification notification = NotificationStruct.INSTANCE.chargeMentionDTO2PO(notificationDTO);
		notificationService.save(notification);

		CapitalAccount capitalAccountUpdate = new CapitalAccount();
		capitalAccountUpdate.setId(capitalAccount.getId());
		BigDecimal sub = NumberUtil.sub(capitalAccount.getAvailable(), withdrawalRecord.getQuantity());
		capitalAccountUpdate.setAvailable(sub);
//		BigDecimal add = NumberUtil.add(String.valueOf(sub), capitalAccount.getFrozen());
//		capitalAccountUpdate.setTotalAssets(String.valueOf(add));
		capitalAccountService.updateById(capitalAccountUpdate);

		stringRedisTemplate.delete("wallet:email:code:" + userId);

		return R.ok("提现申请成功！");
	}

	/**
	 * 后台审核
	 */
	@Inner(value = false)
	@ApiOperation(value = "后台审核", notes = "后台审核")
	@PostMapping("/examine")
	@Transactional(rollbackFor = Exception.class)
	public R examine(@RequestBody WithdrawalRecord withdrawalRecord) {
		WithdrawalRecord withdrawalRecordUpdate = new WithdrawalRecord();
		withdrawalRecordUpdate.setId(withdrawalRecord.getId());
		if (WalletConstant.TRUE.equals(withdrawalRecord.getApprove())) {
			withdrawalRecordUpdate.setState(WalletStatusEnum.WITHDRAWING.getStatus());
			withdrawalRecordUpdate.setTransactionHash(withdrawalRecord.getTransactionHash());
			withdrawalRecordUpdate.setSourceAddress(withdrawalRecord.getSourceAddress());
			withdrawalRecordUpdate.setPublicChain(withdrawalRecord.getPublicChain());
			withdrawalRecordService.updateById(withdrawalRecordUpdate);
			// 查询区块链广播结果
			rabbitTemplate.convertAndSend("wallet.drive.exchange", "wallet.drive.withdrawal.binding", withdrawalRecord.getId());
		} else {
			CapitalAccount capitalAccount = capitalAccountService.getOne(new LambdaQueryWrapper<CapitalAccount>()
					.eq(CapitalAccount::getUserId, withdrawalRecord.getUserId())
			);
			// 根据id获取提现申请记录
			WithdrawalRecord withdrawalRecordInfo = withdrawalRecordService.getOne(new LambdaQueryWrapper<WithdrawalRecord>()
					.select(WithdrawalRecord::getQuantity)
					.eq(WithdrawalRecord::getId, withdrawalRecord.getId()));

			CapitalAccount capitalAccountUpdate = new CapitalAccount();
			capitalAccountUpdate.setId(capitalAccount.getId());
			BigDecimal addAvailable = NumberUtil.add(capitalAccount.getAvailable(), withdrawalRecordInfo.getQuantity());
			capitalAccountUpdate.setAvailable(addAvailable);
//			BigDecimal add = NumberUtil.add(String.valueOf(addAvailable), capitalAccount.getFrozen());
//			capitalAccountUpdate.setTotalAssets(String.valueOf(add));
			capitalAccountService.updateById(capitalAccountUpdate);
			withdrawalRecordUpdate.setState(WalletStatusEnum.REJECTED.getStatus());
			withdrawalRecordService.updateById(withdrawalRecordUpdate);

//			User user = remoteRippleUserService.getUserByUserId(withdrawalRecord.getUserId(), SecurityConstants.FROM_IN).getData();
//
//			String mailSmtpHost = ParamResolver.getStr("MAIL_SMTP_HOST");
//			String mailTransportProtocol = ParamResolver.getStr("MAIL_TRANSPORT_PROTOCOL");
//			String mailUser = ParamResolver.getStr("MAIL_USER");
//			String mailPassword = ParamResolver.getStr("MAIL_PASSWORD");
//
//			JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
//			javaMailSender.setHost(mailSmtpHost);
//			javaMailSender.setProtocol(mailTransportProtocol);
//			javaMailSender.setUsername(mailUser);
//			javaMailSender.setPassword(mailPassword);
//
//			SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
//			simpleMailMessage.setText("提现审核失败");
//			simpleMailMessage.setTo(user.getEmail());
//			simpleMailMessage.setFrom(mailUser);
//			javaMailSender.send(simpleMailMessage);

		}
		return R.ok();
	}

	/**
	 * app用户提现记录
	 */
	@ApiOperation(value = "app用户提现记录", notes = "app用户提现记录")
	@GetMapping("/app/page")
	public R appPage(Page page, WithdrawalRecord withdrawalRecord) {
		Long userId = SecurityUtils.getUser().getId();
		Page appPage = withdrawalRecordService.page(page, new LambdaQueryWrapper<WithdrawalRecord>()
				.eq(WithdrawalRecord::getUserId, userId)
				.in(StrUtil.equals(withdrawalRecord.getState(), WalletStatusEnum.ALL.getStatus()), WithdrawalRecord::getState, WalletStatusEnum.UNDER_REVIEW.getStatus(), WalletStatusEnum.WITHDRAWING.getStatus(), WalletStatusEnum.WITHDRAWAL_COMPLETED.getStatus(), WalletStatusEnum.REJECTED.getStatus())
				.eq(!StrUtil.equals(withdrawalRecord.getState(), WalletStatusEnum.ALL.getStatus()), WithdrawalRecord::getState, withdrawalRecord.getState())
				.ge(withdrawalRecord.getStartTime() != null, WithdrawalRecord::getCreateTime, withdrawalRecord.getStartTime())
				.le(withdrawalRecord.getEndTime() != null, WithdrawalRecord::getCreateTime, withdrawalRecord.getEndTime())
				.orderByDesc(WithdrawalRecord::getCreateTime)
		);
		return R.ok(appPage);
	}

	/**
	 * app用户提现记录根据id获取
	 */
	@ApiOperation(value = "app用户提现记录根据id获取", notes = "app用户提现记录根据id获取")
	@GetMapping("/app/{id}")
	public R appPage(@PathVariable("id") Long id) {
		WithdrawalRecord withdrawalRecord = withdrawalRecordService.getById(id);
		return R.ok(withdrawalRecord);
	}

	/**
	 * web根据用户id获取提现记录列表
	 *
	 * @param id 用户id
	 * @return 提现记录 - 分页
	 */
	@ApiOperation(value = "web根据用户id获取提现记录列表", notes = "web根据用户id获取提现记录列表")
	@GetMapping("/page/user")
	public R<Page<WithdrawalRecord>> getListByUserId(Page<WithdrawalRecord> page, Long id) {
		try {
			Page<WithdrawalRecord> selectPage = withdrawalRecordService.page(page, new QueryWrapper<WithdrawalRecord>() {{
				eq("user_id", id);
				eq("del_flag", "0");
			}});
			return R.ok(selectPage);
		} catch (Exception e) {
			return null;
		}
	}

}
